package com.xhh.preenroll.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.utils.thread.ThreadLocalUtil;
import com.xhh.apis.check.ICheckClient;
import com.xhh.apis.user.IUserClient;
import com.xhh.common.constants.CheckedConstants;
import com.xhh.common.constants.InterviewConstants;
import com.xhh.common.constants.PreenrollConstants;
import com.xhh.common.constants.ReapplyConstants;
import com.xhh.common.redis.CacheService;
import com.xhh.model.check.vos.CheckedVo;
import com.xhh.model.common.dtos.PageResponseResult;
import com.xhh.model.common.dtos.ResponseResult;
import com.xhh.model.common.enums.AppHttpCodeEnum;
import com.xhh.model.interview.pojos.Interview;
import com.xhh.model.interview.vos.InterviewVo;
import com.xhh.model.preenroll.dtos.CancelStatusDto;
import com.xhh.model.preenroll.dtos.PreenrollPageDto;
import com.xhh.model.preenroll.dtos.SendNoticeDto;
import com.xhh.model.preenroll.dtos.UpdateStatusDto;
import com.xhh.model.preenroll.pojos.Preenroll;
import com.xhh.model.preenroll.vos.PreenrollVo;
import com.xhh.model.user.pojos.Student;
import com.xhh.model.user.pojos.User;
import com.xhh.preenroll.mapper.PreenrollMapper;
import com.xhh.preenroll.service.IPreenrollService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xhh
 * @since 2024-08-07
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PreenrollServiceImpl extends ServiceImpl<PreenrollMapper, Preenroll> implements IPreenrollService {

    private final IUserClient userClient;
    private final ICheckClient checkClient;
    private final CacheService cacheService;
    private final RabbitTemplate rabbitTemplate;
    /**
     * 发送待录取通知
     * @param dto
     * @return
     */
    @Override
    public ResponseResult notice(SendNoticeDto dto) {
        // 1. 校验参数
        if (StrUtil.isEmpty(dto.getTitle()) || StrUtil.isEmpty(dto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        User user = ThreadLocalUtil.getUser();
        // 校验身份
        ResponseResult response = checkClient.checkIdentity(user.getId());
        String json = (String) response.getData();
        CheckedVo checked = JSONObject.parseObject(json, CheckedVo.class);
        if (!checked.getIdentityCode().equals(CheckedConstants.SCHOOL_IDENTITY_CODE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        // 获取考生姓名
        ResponseResult result = userClient.getStuByCode(dto.getStuCode());
        String jsonStr = JSON.toJSONString(result.getData());
        Student student = JSONObject.parseObject(jsonStr, Student.class);
        // 2. 构建插入条件
        Preenroll preenroll = BeanUtil.copyProperties(dto, Preenroll.class);
        preenroll.setUserId(user.getId());
        preenroll.setStatus(PreenrollConstants.NOTICE_STATUS_WAITING_ACCEPT);
        preenroll.setSendTime(new Date());
        save(preenroll);
        // 发送短信通知
        HashMap<String, String> msg = new HashMap<>();
        msg.put("phoneNumbers", dto.getAccountPhone());
        msg.put("stuName", student.getName());
        msg.put("majorName", dto.getMajorName());
        msg.put("msg", dto.getContent());
        try {
            rabbitTemplate.convertAndSend(
                    PreenrollConstants.EXCHANGE_NAME,
                    PreenrollConstants.SEND_MESSAGE_KEY,
                    msg
            );
        } catch (AmqpException e) {
            log.error("发送短信通知的消息发送失败, 异常信息: {}", e);
        }
        // 异步通知复试通知微服务删除记录
        try {
            rabbitTemplate.convertAndSend(
                    InterviewConstants.EXCHANGE_NAME,
                    InterviewConstants.DELETE_INTERVIEW_KEY,
                    dto.getIId()
            );
        } catch (AmqpException e) {
            log.error("删除复试通知记录的消息发送失败, 复试通知id：{}", dto.getIId(), e);
        }
        // 3. 返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 查看复试通知
     * @return
     */
    @Override
    public ResponseResult getNotice() {
        // 1. 获取登录用户id
        User user = ThreadLocalUtil.getUser();
        // 2. 校验身份
        ResponseResult response = checkClient.checkIdentity(user.getId());
        String json = (String) response.getData();
        CheckedVo checked = JSONObject.parseObject(json, CheckedVo.class);
        if (!checked.getIdentityCode().equals(CheckedConstants.STUDENT_IDENTITY_CODE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        // 3. 查询复试通知表
        // 3.1 获取考生的准考证号
        ResponseResult result = userClient.getStuByUId(user.getId());
        String string = JSON.toJSONString(result.getData());
        Student student = JSONObject.parseObject(string, Student.class);
        // 3.2 构建查询条件
        List<Preenroll> list = lambdaQuery().eq(Preenroll::getStuCode, student.getStuNo()).list();
//        if (CollUtil.isEmpty(list)) {
//            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
//        }
        // 如果缓存不为空，则优先从缓存中获取
        String key = PreenrollConstants.NOTICE_SCHOOL_CANCEL_KEY + "_" + student.getStuNo();
        String value = cacheService.get(key);
        if (StrUtil.isNotEmpty(value)) {
            Preenroll preenroll = JSONObject.parseObject(value, Preenroll.class);
            // 如果id一样，且通知发送时间为最新的，替换
            for (Preenroll item : list) {
                if (item.getId().equals(preenroll.getId())
                        && item.getSendTime().getTime() < preenroll.getSendTime().getTime()) {
                    list.remove(item);
                    list.add(preenroll);
                }
            }
        }
        // 4. 返回结果
        return ResponseResult.okResult(list);
    }

    /**
     * 考生接收或者拒绝待录取通知
     * @param dto
     * @return
     */
    @Override
    public ResponseResult markNoticeStatusAcceptOrRefuseByStudent(UpdateStatusDto dto) {
        // 1. 校验参数
        if (dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 1.1 获取登录用户id
        User user = ThreadLocalUtil.getUser();
        // 1.2 校验身份
        ResponseResult response = checkClient.checkIdentity(user.getId());
        String json = (String) response.getData();
        CheckedVo checked = JSONObject.parseObject(json, CheckedVo.class);
        if (!checked.getIdentityCode().equals(CheckedConstants.STUDENT_IDENTITY_CODE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        // 1.3 查询复试通知表
        // 获取考生的准考证号
        ResponseResult result = userClient.getStuByUId(user.getId());
        String string = JSON.toJSONString(result.getData());
        Student student = JSONObject.parseObject(string, Student.class);
        // 2. 更新复试通知表状态
        // 同意
        if (dto.getOperation().equals(PreenrollConstants.NOTICE_OPERATION_ACCEPT)) {
            // 如果已经有同意的待录取通知，则不能再进行同意操作
            Preenroll preenroll = lambdaQuery()
                    .eq(Preenroll::getStuCode, student.getStuNo())
                    .eq(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_ACCEPT)
                    .one();
            if (preenroll != null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.ONLY_EXIT_ONE_ACCEPT_PREENROLL);
            }
            lambdaUpdate()
                    .set(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_ACCEPT)
                    .eq(Preenroll::getId, dto.getId())
                    .update();
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        // 拒绝
        if (dto.getOperation().equals(PreenrollConstants.NOTICE_OPERATION_REFUSE)) {
            lambdaUpdate()
                    .set(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_REFUSE)
                    .eq(Preenroll::getId, dto.getId())
                    .update();
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        // 3. 返回结果
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }

    /**
     * 分页条件查询复试通知
     * @param dto
     * @return
     */
    @Override
    public ResponseResult getNoticeByPageAndCondition(PreenrollPageDto dto) {
        // 1. 分页参数校验
        dto.checkParam();
        // 校验用户身份
        User user = ThreadLocalUtil.getUser();
        ResponseResult response = checkClient.checkIdentity(user.getId());
        String json = (String) response.getData();
        CheckedVo checked = JSONObject.parseObject(json, CheckedVo.class);
        if (!checked.getIdentityCode().equals(CheckedConstants.SCHOOL_IDENTITY_CODE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        // 2. 构建分页查询参数
        Page<Preenroll> page = new Page<>(dto.getPage(), dto.getSize());
        page = lambdaQuery()
                .eq(Preenroll::getUserId, user.getId())
                .eq(StrUtil.isNotEmpty(dto.getChoiceFaultyCode()), Preenroll::getFaultyCode, dto.getChoiceFaultyCode())
                .eq(StrUtil.isNotEmpty(dto.getChoiceMajorCode()), Preenroll::getMajorCode, dto.getChoiceMajorCode())
                .eq(StrUtil.isNotEmpty(dto.getStatus()), Preenroll::getStatus, dto.getStatus())
                .page(page);
        // 处理返回结果
        List<Preenroll> records = page.getRecords();
        List<PreenrollVo> list = records.stream().map(record -> {
            // 根据准考证号获取考生姓名
            Student stu = getStuByCode(record);
            PreenrollVo vo = BeanUtil.copyProperties(record, PreenrollVo.class);
            vo.setStuName(stu.getName());
            // 如果缓存不为空，则优先从缓存中获取
            String key = PreenrollConstants.NOTICE_STUDENT_UNDO_KEY + "_" + record.getId();
            String value = cacheService.get(key);
            if (StrUtil.isNotEmpty(value)) {
                Preenroll preenroll = JSONObject.parseObject(value, Preenroll.class);
                // 如果id一样，且通知发送时间为最新的，替换
                if (record.getId().equals(preenroll.getId())) {
                    vo = BeanUtil.copyProperties(preenroll, PreenrollVo.class);
                    vo.setStuName(stu.getName());
                    return vo;
                }
            }
            return vo;
        }).collect(Collectors.toList());
        // 3. 返回结果
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(list);
        return responseResult;
    }

    /**
     * 招生单位取消考生的待录取资格
     * @param pId
     * @return
     */
    @Override
    public ResponseResult cancelStuQualification(Long pId) {
        // 1. 校验参数
        if (pId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 2. 更新状态
        // 2.1 幂等校验
        Preenroll preenroll = getById(pId);
        if (!preenroll.getStatus().equals(PreenrollConstants.NOTICE_STATUS_ACCEPT)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_NOTICE_ACCEPT_STATUS);
        }
        // 2.2 更新数据库
            /*lambdaUpdate()
                    .set(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_SCHOOL_CANCEL)
                    .eq(Preenroll::getId, dto.getId())
                    .update();*/
        // 2.2 把数据存入redis缓存
        preenroll.setStatus(PreenrollConstants.NOTICE_STATUS_SCHOOL_CANCEL);
        preenroll.setSendTime(new Date());
        String key = PreenrollConstants.NOTICE_SCHOOL_CANCEL_KEY + "_" + preenroll.getStuCode();
        String value = JSON.toJSONString(preenroll);
        cacheService.append(key, value);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 考生是否同意招生单位取消待录取资格
     * @param dto
     * @return
     */
    @Override
    public ResponseResult isAcceptCancel(CancelStatusDto dto) {
        // 1. 校验参数
        if (dto.getId() == null || StrUtil.isEmpty(dto.getStuCode())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 优先从redis中获取
        String key = PreenrollConstants.NOTICE_SCHOOL_CANCEL_KEY + "_" + dto.getStuCode();
        String value = cacheService.get(key);
        Preenroll preenroll = JSONObject.parseObject(value, Preenroll.class);
        // 2. 更新状态
        // 2.1 幂等校验
        if (!preenroll.getStatus().equals(PreenrollConstants.NOTICE_STATUS_SCHOOL_CANCEL)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_NOTICE_SCHOOL_CANCEL_STATUS);
        }
        // 同意
        if (dto.getOperation().equals(PreenrollConstants.NOTICE_OPERATION_ACCEPT)) {
            // 2.2 更新数据库
            lambdaUpdate()
                    .set(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_CANCEL)
                    .eq(Preenroll::getId, dto.getId())
                    .update();
            // 移除缓存
            cacheService.delete(key);
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        // 拒绝
        if (dto.getOperation().equals(PreenrollConstants.NOTICE_OPERATION_REFUSE)) {
            // 2.2 更新数据库
            /*lambdaUpdate()
                    .set(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_ACCEPT)
                    .eq(Preenroll::getId, dto.getId())
                    .update();*/
            // 移除缓存
            cacheService.delete(key);
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }

    /**
     * 考生申请解除已同意的待录取
     * @param pId
     * @return
     */
    @Override
    public ResponseResult undoAccept(Long pId) {
        // 1. 校验参数
        if (pId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 2. 发出申请
        // 2.1 幂等校验
        Preenroll preenroll = getById(pId);
        if (!preenroll.getStatus().equals(PreenrollConstants.NOTICE_STATUS_ACCEPT)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_NOTICE_ACCEPT_STATUS);
        }
        // 2.2 把数据存入redis缓存
        preenroll.setStatus(PreenrollConstants.NOTICE_STATUS_STUDENT_UNDO);
        preenroll.setSendTime(new Date());
        String key = PreenrollConstants.NOTICE_STUDENT_UNDO_KEY + "_" + pId;
        String value = JSON.toJSONString(preenroll);
        cacheService.append(key, value);
        // 3. 返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 招生单位是否同意考生解除待录取的申请
     * @param dto
     * @return
     */
    @Override
    public ResponseResult isAcceptRequest(UpdateStatusDto dto) {
        // 1. 校验参数
        if (dto.getId() == null || dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 优先从redis中获取
        String key = PreenrollConstants.NOTICE_STUDENT_UNDO_KEY + "_" + dto.getId();
        String value = cacheService.get(key);
        if (StrUtil.isNotEmpty(value)) {
            Preenroll preenroll = JSONObject.parseObject(value, Preenroll.class);
            if (!preenroll.getStatus().equals(PreenrollConstants.NOTICE_STATUS_STUDENT_UNDO)) {
                return ResponseResult.errorResult(AppHttpCodeEnum.NEED_NOTICE_STUDENT_UNDO_STATUS);
            }
            // 2. 更新状态
            // 同意
            if (dto.getOperation().equals(PreenrollConstants.NOTICE_OPERATION_ACCEPT)) {
                // 2.2 更新数据库
                lambdaUpdate()
                        .set(Preenroll::getStatus, PreenrollConstants.NOTICE_STATUS_REFUSE)
                        .eq(Preenroll::getId, dto.getId())
                        .update();
                // 移除缓存
                cacheService.delete(key);
                return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
            }
            // 拒绝
            if (dto.getOperation().equals(PreenrollConstants.NOTICE_OPERATION_REFUSE)) {
                // 移除缓存
                cacheService.delete(key);
                return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
            }
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }

    private Student getStuByCode(Preenroll record) {
        ResponseResult res = userClient.getStuByCode(record.getStuCode());
        String jsonString = JSON.toJSONString(res.getData());
        return JSONObject.parseObject(jsonString, Student.class);
    }
}
